//----------------------------------*-C++-*----------------------------------//
/*!
 * \file   Psi_Cell_Field.hh
 * \author Jeremy Roberts
 * \date   Jul 6, 2011
 * \brief  Cell angular fluxes
 * \note   Copyright (C) 2011 Jeremy Roberts. 
 */
//---------------------------------------------------------------------------//
// $Rev::                                               $:Rev of last commit
// $Author::                                            $:Author of last commit
// $Date::                                              $:Date of last commit
//---------------------------------------------------------------------------//

#ifndef PSI_CELL_FIELD_HH_
#define PSI_CELL_FIELD_HH_

#include "tran/Cell_Field.hh"

namespace slabtran
{

//===========================================================================//
/*!
 * \class Psi_Cell_Field
 * \brief A container of cell angular flux unknowns.
 *
 * This container holds and allows access to cell-centered angular fluxes
 * for a single energy group.  Typical use won't require storage of these
 * fluxes, but they are needed for debugging, generating contributon fluxes,
 * and other things.  Fluxes are accessed by location, octant, and angle.
 *
 * \tparam <Equations> equation type
 * \tparam <D>         dimension
 *
 * \todo Make accessors more like moments accessors.
 *
 */
 /*!
 * \example test/testPsi_Cell_Field.cc
 *
 * Test of Psi_Cell_Field.
 *
 */
//===========================================================================//

template <class Equations, class D>
class Psi_Cell_Field : public Cell_Field<double>
{

public:

  //!\name TYPEDEFS
  //\{
  typedef typename util::SP<Psi_Cell_Field<Equations, D> > SP_psi_cell_field;
  typedef Cell_Field<double> Base;
  typedef typename Base::value_type value_type;
  typedef typename Base::reference reference;
  typedef typename Base::const_reference const_reference;
  typedef typename Base::pointer pointer;
  typedef typename Base::const_pointer const_pointer;
  typedef typename Base::iterator iterator;
  typedef typename Base::const_iterator const_iterator;
  typedef typename Base::size_type size_type;
  typedef typename Base::difference_type difference_type;
  // convenience type
  typedef typename Base::SP_mesh SP_mesh;
  //\}

  /*!
   * \brief Constructor.
   *
   * \param mesh              Mesh we live on.
   * \param number_angles     Actual total number of angles.
   * \param init_val          Initial value for all members of field.
   *
   * \note
   * The template argument Equations is used for the number of cells.  Hence,
   * this absolutely must be a member function (and suggests we use an
   * abstract base)
   *
   */
  Psi_Cell_Field(SP_mesh mesh, int number_angles, double init_val = 0.0);

  /// \name Accessors
  //\{

  /*!
   * \brief Mutable access to angular flux.
   *
   * This is the general interface for 3-d.  Both 2-d and 1-d use this
   * via their own interfaces, though these are <em>not</em> template
   * specializations. Specialization on a two-parameter template is
   * cumbersome, so it is easiest simply to offer all three interfaces
   * to the moments by default. However, the "contract" for each is
   * <em>dimension-specific</em>.
   *
   * \param     i           x index
   * \param     j           y index
   * \param     k           z index
   * \param     unknown     cell unknown (depends on \em Equations)
   * \param     angle       angle cardinal index.
   * \return                Mutable reference to angular flux value.
   */
  value_type& operator()(int i, int j, int k, int unknown, int angle);

  /*!
   * \brief Return order \f$(l,m)\f$ at \f$(i,j)\f$ for a given cell unknown.
   *
   * This is the interface for use in 2-d computations.
   *
   * \param     i           x index
   * \param     j           y index
   * \param     unknown     cell unknown (depends on \em Equations)
   * \param     angle       angle cardinal index.
   * \return                Mutable reference to angular flux value.
   */
  value_type& operator()(int i, int j, int unknown, int angle);

   /*!
   * \brief Mutable access to angular flux.
   *
   * This is the interface for use in 1-d computations.
   *
   * \param     i           x index
   * \param     unknown     cell unknown (depends on \em Equations)
   * \param     angle       angle cardinal index.
   * \return                Mutable reference to angular flux value.
   */
  value_type& operator()(int i, int unknown, int angle);

  /*!
   * \brief Const access to angular flux.
   *
   * This is the general interface for 3-d.  Both 2-d and 1-d use this
   * via their own interfaces, though these are <em>not</em> template
   * specializations. Specialization on a two-parameter template is
   * cumbersome, so it is easiest simply to offer all three interfaces
   * to the moments by default. However, the "contract" for each is
   * <em>dimension-specific</em>.
   *
   * \param     i           x index
   * \param     j           y index
   * \param     k           z index
   * \param     unknown     cell unknown (depends on \em Equations)
   * \param     angle       angle cardinal index.
   * \return                Const reference to angular flux value.
   */
  const value_type& operator()(int i, int j, int k,
                               int unknown, int angle) const;

  /*!
   * \brief Return order \f$(l,m)\f$ at \f$(i,j)\f$ for a given cell unknown.
   *
   * This is the interface for use in 2-d computations.
   *
   * \param     i           x index
   * \param     j           y index
   * \param     unknown     cell unknown (depends on \em Equations)
   * \param     angle       angle cardinal index.
   * \return                Const reference to angular flux value.
   */
  const value_type& operator()(int i, int j,
                               int unknown, int angle) const;

   /*!
   * \brief Const access to angular flux.
   *
   * This is the interface for use in 1-d computations.
   *
   * \param     i           x index
   * \param     unknown     cell unknown (depends on \em Equations)
   * \param     angle       angle cardinal index.
   * \return                Const reference to angular flux value.
   */
  const value_type& operator()(int i, int unknown, int angle) const;

  /// Return number of angles per unknown.
  int number_angles(){ return d_number_angles; };

  //\}

private:

  /// Number of angles in angular mesh.
  const int d_number_angles;

};

} // end namespace slabtran

//---------------------------------------------------------------------------//
// INLINE FUNCTIONS
//---------------------------------------------------------------------------//

#include "Psi_Cell_Field.i.hh"


#endif /* PSI_CELL_FIELD_HH_ */

//---------------------------------------------------------------------------//
//              end of Psi_Cell_Field.hh
//---------------------------------------------------------------------------//
